#ifndef ETL_SIMD_HPP
# define ETL_SIMD_HPP
# pragma once

#if defined(__i386__) || defined(__x86_64__)
# include <x86intrin.h>
#endif

#if defined(__ARM_NEON__)
# include <arm_neon.h>
#endif // __ARM_NEON

namespace etl
{

#if defined(__SSE__)
  template <::std::size_t a, ::std::size_t ...Is, typename E>
  inline typename ::std::enable_if<!is_vector<E>{} ||
    ((detail::map_extent<E::dimension>{} - a) < 4),
    __m128>::type
  get_m128f(E const& e)
  {
    return __m128{e(a), e(Is)...};
  }

  template <::std::size_t a, ::std::size_t ...Is, typename E>
  inline typename ::std::enable_if<is_vector<E>{} &&
    ((detail::map_extent<E::dimension>{} - a) >= 4),
    __m128 const&
  >::type
  get_m128f(E const& e)
  {
    return *reinterpret_cast<__m128 const*>(e.cdata() + a);
  }
#endif // __SSE__

#if defined(__SSE2__)
  template <::std::size_t a, ::std::size_t ...Is, typename E>
  inline typename ::std::enable_if<!is_vector<E>{} ||
    ((detail::map_extent<E::dimension>{} - a) < 2),
    __m128d
  >::type
  get_m128d(E const& e)
  {
    return __m128d{e(a), e(Is)...};
  }

  template <::std::size_t a, ::std::size_t ..., typename E>
  inline typename ::std::enable_if<is_vector<E>{} &&
    ((detail::map_extent<E::dimension>{} - a) >= 2),
    __m128d const&
  >::type
  get_m128d(E const& e)
  {
    return *reinterpret_cast<__m128d const*>(e.cdata() + a);
  }
#endif // __SSE2__

}

#endif // ETL_SIMD_HPP
